package edu.northwestern.cbits.purple_robot_manager.probes.media;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.support.v4.app.NotificationCompat;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import edu.northwestern.cbits.purple_robot_manager.R;
import edu.northwestern.cbits.purple_robot_manager.activities.StartActivity;
import edu.northwestern.cbits.purple_robot_manager.activities.settings.FlexibleListPreference;
import edu.northwestern.cbits.purple_robot_manager.activities.settings.SettingsActivity;
import edu.northwestern.cbits.purple_robot_manager.logging.LogManager;
import edu.northwestern.cbits.purple_robot_manager.logging.SanityCheck;
import edu.northwestern.cbits.purple_robot_manager.probes.Probe;
public class AudioCaptureProbe extends Probe
{
private static final boolean DEFAULT_ENABLED = false;
private static final String ENABLED = "config_probe_audio_capture_enabled";
private static final String FREQUENCY = "config_probe_audio_capture_frequency";
private static final String DURATION = "config_probe_audio_capture_duration";
private static final String DEFAULT_DURATION = "15000";
private static final int NOTE_ID = 684756384;
private static final String RECORDING_DURATION = "RECORDING_DURATION";
private boolean _recording = false;
private long _lastCheck = System.currentTimeMillis();
@Override
public String getPreferenceKey() {
return "media_audio-capture";
}
@Override
public String name(Context context)
{
return "edu.northwestern.cbits.purple_robot_manager.probes.media.AudioCaptureProbe";
}
@Override
public String title(Context context)
{
return context.getString(R.string.title_audio_capture_probe);
}
@Override
public String probeCategory(Context context)
{
return context.getString(R.string.probe_media_capture_category);
}
@Override
@SuppressWarnings("deprecation")
public PreferenceScreen preferenceScreen(Context context, PreferenceManager manager)
{
PreferenceScreen screen = super.preferenceScreen(context, manager);
screen.setTitle(this.title(context));
screen.setSummary(this.summary(context));
CheckBoxPreference enabled = new CheckBoxPreference(context);
enabled.setTitle(R.string.title_enable_probe);
enabled.setKey(AudioCaptureProbe.ENABLED);
enabled.setDefaultValue(AudioCaptureProbe.DEFAULT_ENABLED);
screen.addPreference(enabled);
FlexibleListPreference frequency = new FlexibleListPreference(context);
frequency.setKey(AudioCaptureProbe.FREQUENCY);
frequency.setEntryValues(R.array.probe_satellite_frequency_values);
frequency.setEntries(R.array.probe_satellite_frequency_labels);
frequency.setTitle(R.string.probe_frequency_label);
frequency.setDefaultValue(Probe.DEFAULT_FREQUENCY);
screen.addPreference(frequency);
FlexibleListPreference duration = new FlexibleListPreference(context);
duration.setKey(AudioCaptureProbe.DURATION);
duration.setEntryValues(R.array.probe_audio_feature_duration_values);
duration.setEntries(R.array.probe_audio_feature_duration_labels);
duration.setTitle(R.string.probe_audio_feature_duration_label);
duration.setDefaultValue(AudioCaptureProbe.DEFAULT_DURATION);
screen.addPreference(duration);
return screen;
}
@Override
public boolean isEnabled(final Context context)
{
if (super.isEnabled(context))
{
SharedPreferences prefs = Probe.getPreferences(context);
final AudioCaptureProbe me = this;
boolean enabled = prefs.getBoolean(AudioCaptureProbe.ENABLED, AudioCaptureProbe.DEFAULT_ENABLED);
if (this._recording == false && enabled)
{
final long now = System.currentTimeMillis();
long freq = Long.parseLong(prefs.getString(AudioCaptureProbe.FREQUENCY, Probe.DEFAULT_FREQUENCY));
final int duration = Integer.parseInt(prefs.getString(AudioCaptureProbe.DURATION, AudioCaptureProbe.DEFAULT_DURATION));
if (now - this._lastCheck > freq) {
this._recording = true;
final NotificationManager noteManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(context, AudioCaptureProbe.NOTE_ID, new Intent(context, StartActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder = builder.setContentIntent(contentIntent);
builder = builder.setContentTitle(context.getString(R.string.notify_audio_recording_active));
builder.setOngoing(true);
builder = builder.setSmallIcon(R.drawable.ic_note_mic);
builder = builder.setContentText(context.getString(R.string.notify_audio_recording_active_details));
builder = builder.setTicker(context.getString(R.string.notify_audio_recording_active));
Notification note = builder.build();
noteManager.notify(AudioCaptureProbe.NOTE_ID, note);
Runnable r = new Runnable() {
@Override
@SuppressWarnings("deprecation")
public void run() {
final Bundle bundle = new Bundle();
bundle.putString("PROBE", me.name(context));
bundle.putLong("TIMESTAMP", System.currentTimeMillis() / 1000);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
File internalStorage = context.getCacheDir();
if (SettingsActivity.useExternalStorage(context))
internalStorage = context.getExternalCacheDir();
if (internalStorage != null && !internalStorage.exists())
internalStorage.mkdirs();
File audioFolder = new File(internalStorage, "Audio Capture Probe Audio");
if (audioFolder != null && !audioFolder.exists())
audioFolder.mkdirs();
final File audioFile = new File(audioFolder, now + ".mp4");
final String filename = audioFile.getAbsolutePath();
try {
final MediaRecorder recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setOutputFile(filename);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
recorder.prepare();
final long start = System.currentTimeMillis();
recorder.start();
Runnable stop = new Runnable()
{
public void run()
{
try
{
Thread.sleep(duration);
}
catch (InterruptedException e)
{
}
recorder.stop();
long end = System.currentTimeMillis();
recorder.release();
bundle.putLong(AudioCaptureProbe.RECORDING_DURATION, end - start);
bundle.putString(Probe.PROBE_MEDIA_URL, Uri.fromFile(audioFile).toString());
bundle.putString(Probe.PROBE_MEDIA_CONTENT_TYPE, "audio/mp4");
me.transmitData(context, bundle);
noteManager.cancel(AudioCaptureProbe.NOTE_ID);
me._recording = false;
}
};
Thread stopThread = new Thread(stop);
stopThread.start();
}
catch (IOException e)
{
LogManager.getInstance(context).logException(e);
me._recording = false;
noteManager.cancel(AudioCaptureProbe.NOTE_ID);
}
catch (IllegalStateException e)
{
LogManager.getInstance(context).logException(e);
me._recording = false;
noteManager.cancel(AudioCaptureProbe.NOTE_ID);
}
}
};
Thread t = new Thread(r);
t.start();
this._lastCheck = now;
}
}
return enabled;
}
return false;
}
@Override
public String summary(Context context)
{
return context.getString(R.string.summary_audio_capture_probe_desc);
}
@Override
public void enable(Context context)
{
SharedPreferences prefs = Probe.getPreferences(context);
Editor e = prefs.edit();
e.putBoolean(AudioCaptureProbe.ENABLED, true);
e.commit();
}
@Override
public void disable(Context context)
{
SharedPreferences prefs = Probe.getPreferences(context);
Editor e = prefs.edit();
e.putBoolean(AudioCaptureProbe.ENABLED, false);
e.commit();
}
@Override
public String summarizeValue(Context context, Bundle bundle)
{
long duration = (long) bundle.getDouble(AudioCaptureProbe.RECORDING_DURATION);
return String.format(context.getResources().getString(R.string.summary_audio_capture_probe), duration);
}
@Override
public JSONObject fetchSettings(Context context)
{
JSONObject settings = super.fetchSettings(context);
try
{
JSONObject frequency = new JSONObject();
frequency.put(Probe.PROBE_TYPE, Probe.PROBE_TYPE_LONG);
JSONArray values = new JSONArray();
String[] options = context.getResources().getStringArray(R.array.probe_satellite_frequency_values);
for (String option : options)
{
values.put(Long.parseLong(option));
}
frequency.put(Probe.PROBE_VALUES, values);
settings.put(Probe.PROBE_FREQUENCY, frequency);
JSONObject duration = new JSONObject();
duration.put(Probe.PROBE_TYPE, Probe.PROBE_TYPE_LONG);
values = new JSONArray();
String[] durationOptions = context.getResources().getStringArray(R.array.probe_audio_feature_duration_values);
for (String option : durationOptions)
{
values.put(Long.parseLong(option));
}
duration.put(Probe.PROBE_VALUES, values);
settings.put(Probe.PROBE_DURATION, duration);
}
catch (JSONException e)
{
LogManager.getInstance(context).logException(e);
}
return settings;
}
@Override
public Map<String, Object> configuration(Context context)
{
Map<String, Object> map = super.configuration(context);
SharedPreferences prefs = Probe.getPreferences(context);
try
{
long freq = Long.parseLong(prefs.getString(AudioCaptureProbe.FREQUENCY, Probe.DEFAULT_FREQUENCY));
map.put(Probe.PROBE_FREQUENCY, freq);
long duration = Long.parseLong(prefs.getString(AudioCaptureProbe.DURATION, AudioCaptureProbe.DEFAULT_DURATION));
map.put(Probe.PROBE_DURATION, duration);
}
catch (NumberFormatException e)
{
LogManager.getInstance(context).logException(e);
}
return map;
}
@Override
public void updateFromMap(Context context, Map<String, Object> params)
{
super.updateFromMap(context, params);
if (params.containsKey(Probe.PROBE_FREQUENCY))
{
Object frequency = params.get(Probe.PROBE_FREQUENCY);
if ((frequency instanceof Double) == false)
frequency = Double.valueOf(frequency.toString()).longValue();
else
frequency = ((Double) frequency).longValue();
SharedPreferences prefs = Probe.getPreferences(context);
Editor e = prefs.edit();
e.putString(AudioCaptureProbe.FREQUENCY, frequency.toString());
e.commit();
}
if (params.containsKey(Probe.PROBE_DURATION))
{
Object duration = params.get(Probe.PROBE_DURATION);
if ((duration instanceof Double) == false)
duration = Double.valueOf(duration.toString()).longValue();
else
duration = ((Double) duration).longValue();
SharedPreferences prefs = Probe.getPreferences(context);
Editor e = prefs.edit();
e.putString(AudioCaptureProbe.DURATION, duration.toString());
e.commit();
}
}
}